"""
The MIT License (MIT)
Copyright © 2022 Walkline Wang (https://walkline.wang)
Gitee: https://gitee.com/walkline/micropython-tft-research
"""
from machine import SPI, Pin
import utime
from sys import exit
import st7789
import os
import esp32
from config import Config

RESOURCE_PARTITION = '/res'


class ResourceManager(object):
	@staticmethod
	def mount_resource_partition() -> bool:
		try:
			os.umount(RESOURCE_PARTITION)
		except OSError as ose:
			if str(ose) == '[Errno 22] EINVAL':
				pass
			else:
				print(ose)

		res = esp32.Partition.find(esp32.Partition.TYPE_DATA, label='resource')

		if res:
			os.mount(res[0], RESOURCE_PARTITION)
			return True
		else:
			return False


def initialize_display():
	spi = SPI(
		1,
		baudrate=40000000,
		polarity=1,
		sck=Pin(Config.Pins.SCL),
		mosi=Pin(Config.Pins.SDA)
	)

	display = st7789.ST7789(
		spi, 240, 240,
		reset=Pin(Config.Pins.RST, Pin.OUT),
		dc=Pin(Config.Pins.DC, Pin.OUT)
	)
	display.init()

	return display

def timed_function(f, *args, **kwargs):
    myname = str(f).split(' ')[1]
    def new_func(*args, **kwargs):
        t = utime.ticks_us()
        result = f(*args, **kwargs)
        delta = utime.ticks_diff(utime.ticks_us(), t)
        print('Function {} Time = {:6.3f}ms'.format(myname, delta/1000))
        return result
    return new_func

@timed_function
def method_1():
	'''method 1 - for test luffy.ppm'''

	ppm_file = f'{RESOURCE_PARTITION}/images/luffy.ppm'

	with open(ppm_file, 'rb') as ppm_file:
		_ = ppm_file.readline()

		size = ppm_file.readline().replace(b'\n', b'').split(b' ')
		ppm_width = int(size[0])
		ppm_height = int(size[1])

		_ = ppm_file.readline()

		for y in range(ppm_height):
			for x in range(ppm_width):
				color888 = ppm_file.read(3)
				color565 = st7789.color565(color888[0], color888[1], color888[2])
				display.pixel(x, y, color565)

@timed_function
def method_2():
	'''method 2 - for test luffy.ppm'''

	ppm_file = f'{RESOURCE_PARTITION}/images/luffy.ppm'

	with open(ppm_file, 'rb') as ppm_file:
		_ = ppm_file.readline()

		size = ppm_file.readline().replace(b'\n', b'').split(b' ')
		ppm_width = int(size[0])
		ppm_height = int(size[1])

		_ = ppm_file.readline()

		ppm_array = bytearray(ppm_width * ppm_height * 2)
		index = 0

		while True:
			color888 = ppm_file.read(3)

			if color888 == b'':
				break

			color565 = st7789.color565(color888[0], color888[1], color888[2])
			ppm_array[index] = color565 >> 8
			ppm_array[index + 1] = color565 & 0x00ff
			index += 2

		display.blit_buffer(ppm_array, 0, 0, ppm_width, ppm_height)

@timed_function
def method_3():
	'''method 3 - for test luffy_240.ppm'''

	ppm_file = 'images/luffy_240.ppm'

	with open(ppm_file, 'rb') as ppm_file:
		_ = ppm_file.readline()

		size = ppm_file.readline().replace(b'\n', b'').split(b' ')
		ppm_width = int(size[0])

		_ = ppm_file.readline()

		blit_height = 30
		ppm_array_length = ppm_width * blit_height * 2
		ppm_array = bytearray(ppm_array_length)
		index = blit_count = 0

		while True:
			color888 = ppm_file.read(3)

			if color888 == b'':
				break

			color565 = (color888[0] & 0xf8) << 8 | (color888[1] & 0xfc) << 3 | color888[2] >> 3
			ppm_array[index] = (color565 & 0xff00) >> 8
			ppm_array[index + 1] = color565 & 0x00ff
			index = (index + 2) % ppm_array_length

			if index == 0:
				display.blit_buffer(ppm_array, 0, blit_count * blit_height, ppm_width, blit_height)
				blit_count += 1

@timed_function
def method_4():
	'''method 4 - for test luffy_240.ppm'''
	# summary:
	# display image		: 2639 ms
	# only read file	: 74 ms
	# convert data		: 2592 ms

	ppm_file = 'images/luffy_240.ppm'

	with open(ppm_file, 'rb') as ppm_file:
		_ = ppm_file.readline()

		size = ppm_file.readline().replace(b'\n', b'').split(b' ')
		ppm_width = int(size[0])

		_ = ppm_file.readline()

		blit_height = 10
		ppm_array_length = ppm_width * blit_height * 2
		ppm_array = bytearray(ppm_array_length)
		index = blit_count = 0

		while True:
			color888 = ppm_file.read(3 * ppm_width * blit_height)

			if color888 == b'':
				break

			for count in range(len(color888) / 3):
				color565 = (color888[count * 3] & 0xf8) << 8 | (color888[count * 3 + 1] & 0xfc) << 3 | color888[count * 3 + 2] >> 3
				ppm_array[index] = color565 >> 8
				ppm_array[index + 1] = color565 & 0x00ff
				index += 2

				if index == ppm_array_length:
					display.blit_buffer(ppm_array, 0, blit_count * blit_height, ppm_width, blit_height)
					blit_count += 1
					index = 0


if __name__ == '__main__':
	if not ResourceManager.mount_resource_partition():
		print('Cannot mount resource partition')
		exit(0)

	display = initialize_display()

	run_test = 4

	if run_test == 1:
		# Function method_1 Time = 888.895ms
		method_1()
	elif run_test == 2:
		# Function method_2 Time = 112.000ms
		method_2()
	elif run_test == 3:
		# Function method_3 Time = 1843.199ms
		method_3()
	else:
		# Function method_4 Time = 1470.925ms
		rotation = 0

		while True:
			display.rotation(rotation)
			method_4()
			rotation = (rotation + 1) % 4
			display.fill(st7789.BLACK)
